package com.wifipositioner.positioning;

import com.wifipositioner.Globals;
import com.wifipositioner.measure.MeasuredPoint;

public class DistanceCalculator {
	
	private double closestDist = Double.MAX_VALUE;
	private String closestRefPointName = "";
	
	public DistanceCalculator(MeasuredPoint targetRefPoint) {
		String[] dominantSSIDs = targetRefPoint.getDominantSSIDs();
		ReferencePointMap domRefPointMap = 
			RefPointCache.get().getRefPointMapByDominantSSID(dominantSSIDs[0]);
		checkRefPointMap(domRefPointMap, targetRefPoint);
		//if the distance is too big in the dominant map
		if(closestDist > Globals.MaxDistForRefPointMatch){
			domRefPointMap = 
				RefPointCache.get().getRefPointMapBySecDominantSSID(dominantSSIDs[1]);
			checkRefPointMap(domRefPointMap, targetRefPoint);
		}
		//if the distance is too big in the secondary dominant map
		if(closestDist > Globals.MaxDistForRefPointMatch){
			checkRefPOintList(targetRefPoint);
		}
		
	}
	private void checkRefPointMap(ReferencePointMap domRefPointMap, MeasuredPoint targetRefPoint){
		for(String domRefPointName : domRefPointMap.keySet()){
			MeasuredPoint refPoint = domRefPointMap.get(domRefPointName);
			double distance = calcDistance(targetRefPoint, refPoint);
			if(distance < closestDist){
				closestDist = distance;
				closestRefPointName = refPoint.getName();
			}
		}
	}
	private void checkRefPOintList(MeasuredPoint targetRefPoint){
		for(MeasuredPoint refPoint : RefPointCache.get().getRefPointList()){
			double distance = calcDistance(targetRefPoint, refPoint);
			if(distance < closestDist){
				closestDist = distance;
				closestRefPointName = refPoint.getName();
			}
		}
		
	}
	private double calcDistance(MeasuredPoint target, MeasuredPoint refPoint){
		double distance = 0;
		double distFromMissingAP = 0;
		for(String targetSSID : target.scanMap.keySet()){
			Double refAP_SS = refPoint.scanMap.get(targetSSID).getAvg();
			Double target_SS = target.scanMap.get(targetSSID).getAvg();
			//if there is no ssid in the refmap
			if(refAP_SS == null){
				distFromMissingAP += Globals.missingWeight * 1 / target_SS;
				continue;
			}
			double tmpDist = (refAP_SS - target_SS) * target.scanMap.get(targetSSID).getLevelWeight();
			distance += tmpDist * tmpDist;
		}
		return Math.sqrt(distance) + distFromMissingAP;
	}
	public double getClosestDist() {
		return closestDist;
	}
	public String getClosestRefPointName() {
		return closestRefPointName;
	}
}
